<?php

namespace App\Service\Facade\Elastic;

use Elastic\Elasticsearch\Client;

class ElasticsearFacadeService
{
    private $client;

    public function __construct(Client $client)
    {
        $this->client = $client;
    }
    /**
     * 统一执行 Elasticsearch 操作并处理异常
     * @param callable $operation 要执行的操作
     * @param string $action 操作描述
     * @param string|null $index 索引名称
     * @param string|null $id 文档 ID
     * @param array|null $data 相关数据
     */
    private function executeElasticsearchOperation(callable $operation, string $action, ?string $index = null, ?string $id = null, ?array $data = null)
    {
        try {
            return [0,$operation()];
        } catch (\Exception $e) {
            return [$e->getCode(),$e->getMessage()];
        }
    }

    /**
     * 创建索引
     * @param string $index 索引名称
     * @param array $settings 索引设置
     * @param array $mappings 索引映射
     */
    public function createIndex(string $index, array $settings = [], array $mappings = [])
    {
        $params = [
            'index' => $index,
            'body' => [
                'settings' => empty($settings) ? (object)[] : $settings,
                'mappings' => empty($mappings) ? (object)[] : $mappings
            ]
        ];

        list($code) =  $this->executeElasticsearchOperation(function () use ($params) {
            return $this->client->indices()->create($params);
        }, '创建索引', $index);

        return $code === 0 ? 1 : 0;
    }

    /**
     * 检查索引是否存在
     * @param string $index 索引名称
     */
    public function indexExists(string $index)
    {
        list($code,$response) = $this->executeElasticsearchOperation(function () use ($index) {
            return $this->client->indices()->exists(['index' => $index]);
        }, '检查索引是否存在', $index);
        return $response->asBool() ? 1 : 0;
    }

    /**
     * 删除索引
     * @param string $index 索引名称
     */
    public function deleteIndex(string $index)
    {
        $this->executeElasticsearchOperation(function () use ($index) {
            return $this->client->indices()->delete(['index' => $index]);
        }, '删除索引', $index);

        return 1;
    }

    /**
     * 添加或更新文档
     * @param string $index 索引名称
     * @param string $id 文档 ID
     * @param array $data 文档数据
     */
    public function indexDocument(string $index, string $id, array $data)
    {
        $params = [
            'index' => $index,
            'id' => $id,
            'body' => $data
        ];

        $this->executeElasticsearchOperation(function () use ($params) {
            return $this->client->index($params);
        }, '添加或更新文档', $index, $id);

        return 1;
    }

    /**
     * 获取文档
     * @param string $index 索引名称
     * @param string $id 文档 ID
     */
    public function getDocument(string $index, string $id)
    {
        $params = [
            'index' => $index,
            'id' => $id
        ];

        list($code, $response) = $this->executeElasticsearchOperation(function () use ($params) {
            return $this->client->get($params);
        }, '获取文档', $index, $id);

        return $code === 0 ? $response['_source'] : null;
    }

    /**
     * 删除文档
     * @param string $index 索引名称
     * @param string $id 文档 ID
     */
    public function deleteDocument(string $index, string $id)
    {
        $params = [
            'index' => $index,
            'id' => $id
        ];

        $this->executeElasticsearchOperation(function () use ($params) {
            return $this->client->delete($params);
        }, '删除文档', $index, $id);

        return 1;
    }


        /**
         * 搜索文档
         * @param string $index 索引名称
         * @param array $query 搜索查询
         * @param array $sort 排序规则
         * @param int $page 页码
         * @param int $size 每页数量
         */
        public function search(string $index, $query = [], $sort = [], int $page = 1, int $size = 10)
        {
            // 构建基础参数
            if ($page < 1) {
                $page = 1;
            }
            if ($size < 1 || $size >= 1000) {
                $size = 10;
            }
            $params = [
                'index' => $index,
                'body' => [
                    'from' => ($page - 1) * $size,
                    'size' => $size,
                ]
            ];

            // 处理查询条件
            if (!empty($query)) {
                $params['body']['query'] = ['bool' => $this->buildBoolQuery($query)];
            } else {
                $params['body']['query'] = ['match_all' => new \stdClass()];
            }

            // 处理排序
            if (!empty($sort)) {
                $params['body']['sort'] = $this->buildSortParams($sort);
            }
            // p($params);die();
            list($code, $response) = $this->executeElasticsearchOperation(function () use ($params) {
                return $this->client->search($params);
            }, '搜索文档', $index, null, $query);
            
            if ($code === 0) {
                return array_map(function($hit) {
                    $source = $hit['_source'] ?? [];
                    $source['id'] = $hit['_id'] ?? null;
                    return $source;
                }, $response['hits']['hits'] ?? []);
            }
            
            return [];
        }

        /**
         * 查询索引文档总数
         * @param string $index 索引名称
         * @param array $query 查询条件（格式同search方法）
         * @return int 符合条件的文档总数
         */
        public function getDocumentCount(string $index, array $query = [])
        {
            $params = [
                'index' => $index,
                'body' => []
            ];

            // 处理查询条件
            if (!empty($query)) {
                $params['body']['query'] = ['bool' => $this->buildBoolQuery($query)];
            } else {
                $params['body']['query'] = ['match_all' => new \stdClass()];
            }

            list($code, $response) = $this->executeElasticsearchOperation(function () use ($params) {
                return $this->client->count($params);
            }, '查询文档总数', $index);

            return $code === 0 ? ($response['count'] ?? 0) : 0;
        }

        /**
         * 构建bool查询条件
         * @param array $query 查询条件数组
         * @return array bool查询结构
         */
        private function buildBoolQuery(array $query): array
        {
            $boolQuery = [
                'must' => [],
                'must_not' => []
            ];

            foreach ($query as $condition) {
                if (is_array($condition) && count($condition) >= 3) {
                    list($field, $operator, $value) = array_pad($condition, 3, null);
                    
                    switch (strtolower($operator)) {
                        case '=':
                        case '==':
                            $boolQuery['must'][] = ['match_phrase' => [$field => $value]];
                            break;
                        case '!=':
                            $boolQuery['must_not'][] = ['term' => [$field => $value]];
                            break;
                        case '>':
                            $boolQuery['must'][] = ['range' => [$field => ['gt' => $value]]];
                            break;
                        case '<':
                            $boolQuery['must'][] = ['range' => [$field => ['lt' => $value]]];
                            break;
                        case '>=':
                            $boolQuery['must'][] = ['range' => [$field => ['gte' => $value]]];
                            break;
                        case '<=':
                            $boolQuery['must'][] = ['range' => [$field => ['lte' => $value]]];
                            break;
                        case 'like':
                            $boolQuery['must'][] = ['match_phrase' => [$field => $value]];
                            break;
                        case 'in':
                            if (is_array($value)) {
                                $boolQuery['must'][] = ['terms' => [$field => $value]];
                            }
                            break;
                    }
                } elseif (is_array($condition) && isset($condition['bool'])) {
                    // 支持嵌套bool查询
                    $boolQuery['must'][] = $condition;
                }
            }

            // 移除空的must_not数组
            if (empty($boolQuery['must_not'])) {
                unset($boolQuery['must_not']);
            }

            return $boolQuery;
        }

        /**
         * 构建排序参数
         * @param array $sort 排序规则
         * @return array 排序参数
         */
        private function buildSortParams(array $sort): array
        {
            $sortParams = [];
            foreach ($sort as $field => $direction) {
                if (is_string($field)) {
                    $sortParams[] = [$field => ['order' => strtolower($direction)]];
                } elseif (is_string($direction)) {
                    // 支持 ['field', 'asc'] 格式
                    $sortParams[] = [$direction => ['order' => 'asc']];
                }
            }
            return $sortParams;
        }    
    // ===================================还未调试==================================================

    /**
     * 批量操作
     * @param array $operations 批量操作数组
     */
    public function bulk(array $operations)
    {
        $params = ['body' => []];
        foreach ($operations as $operation) {
            $params['body'][] = $operation;
        }

        return $this->executeElasticsearchOperation(function () use ($params) {
            return $this->client->bulk($params);
        }, '批量操作', null, null, $operations);
    }

    /**
     * 刷新索引
     * @param string $index 索引名称
     */
    public function refreshIndex(string $index)
    {
        return $this->executeElasticsearchOperation(function () use ($index) {
            return $this->client->indices()->refresh(['index' => $index]);
        }, '刷新索引', $index);
    }

    /**
     * 获取索引状态
     * @param string $index 索引名称
     */
    public function getIndexStatus(string $index)
    {
        return $this->executeElasticsearchOperation(function () use ($index) {
            return $this->client->indices()->stats(['index' => $index]);
        }, '获取索引状态', $index);
    }

    /**
     * 关闭索引
     * @param string $index 索引名称
     */
    public function closeIndex(string $index)
    {
        return $this->executeElasticsearchOperation(function () use ($index) {
            return $this->client->indices()->close(['index' => $index]);
        }, '关闭索引', $index);
    }

    /**
     * 打开索引
     * @param string $index 索引名称
     */
    public function openIndex(string $index)
    {
        return $this->executeElasticsearchOperation(function () use ($index) {
            return $this->client->indices()->open(['index' => $index]);
        }, '打开索引', $index);
    }

    /**
     * 获取所有索引
     */
    public function getAllIndices()
    {
        return $this->executeElasticsearchOperation(function () {
            return $this->client->indices()->getAliases();
        }, '获取所有索引');
    }

    /**
     * 执行聚合查询
     * @param string $index 索引名称
     * @param array $aggregations 聚合查询配置
     */
    public function aggregate(string $index, array $aggregations)
    {
        $params = [
            'index' => $index,
            'body' => [
                'size' => 0,
                'aggs' => $aggregations
            ]
        ];

        return $this->executeElasticsearchOperation(function () use ($params) {
            return $this->client->search($params);
        }, '执行聚合查询', $index, null, $aggregations);
    }
}